package game;

import java.awt.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import xml.XMLizeable;

/**
 * <p>{@code GameType} is the superclass for all types of games involving a 
 * {@code ChessBoard} and {@code Pieces}. It sets up the game at the start 
 * and enforces the rules.</p>
 * 
 * @author Nicole Waldrum
 * @date January 30, 2010
 * @version 1.0
 * 
 * @author Mark Kelly
 * @date February 20, 2010
 * @version 2.0
 *
 */
public abstract class GameType implements MoveChecker, GameStateListener, XMLizeable {
	// Class Variables
	protected static final Dimension DEFAULT_BOARD_SIZE = new Dimension(8,8);
	
	// Instance Variables
	
	protected GameState state;

	// this variable is only to allow the value to persist after the constructor to be used in setupBoard()
	protected Dimension boardSize; 
	
	/**
	 * <p>Initializes a new instance of <tt>GameType</tt> with a default board size</p>
	 */
	public GameType() {
		boardSize = GameType.DEFAULT_BOARD_SIZE;
	}
	
	/**
	 * <p>Initializes a new instance of <tt>GameType</tt> with the specified board size</p>
	 * 
	 * @param boardSize the size of the <tt>ChessBoard</tt> used for this <tt>GameType</tt>
	 */
	public GameType(Dimension boardSize) {
		this.boardSize = boardSize;
	}
	
	/**
	 * <p>Associates this instance of {@code GameType} with a {@code GameType}.</p>
	 * 
	 * @param gameState the {@code GameState} to associate
	 */
	public void setGameState(GameState gameState) {
		this.state = gameState;
		gameState.addGameStateListener(this);
	}
	
	/**
	 * <p>Checks if the conditions for winning this type of game have been met.</p>
	 * @param team the <tt>Team</tt>
	 */
	public abstract boolean hasWon(Team team);
	
	/**
	 * Sets up the board and pieces for this type of game.
	 */
	public abstract void setupBoard();

	/**
	 * <p>Performs any actions that are necessary after a {@code Piece} has been moved.</p>
	 * @param p the {@code Piece} that was moved
	 */
	public abstract void pieceMoved(GameState gs, Piece p, ChessBoard b);
	
	public void gameStarted(GameState gs){
	}
	
	public void stateChanged(GameState gs) {
	}
	
	/**
	 * <p>Take a turn</p>
	 * 
	 * @param start location of the {@code Piece} to move
	 * @param dest location to move the starting {@code Piece} to
	 * @return {@code true} if a turn was taken
	 */
	public abstract boolean takeTurn (Point start, Point dest);

	public static GameType importFromXML (Element elem) {
		GameType type = null;
		String gameType = elem.getAttribute("GameType");
		Class<?> clazz = null;
		Method method = null;

		try {
			clazz = (Class<?>) Class.forName(gameType);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		try {
			method = clazz.getMethod("importFromXML", Element.class);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		
		try {
			type = (GameType) method.invoke(null, elem);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return type;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Element toXML(Document doc) {
		Element gameType = doc.createElement("GameType");
		gameType.setAttribute("GameType", this.getClass().getName());
		return gameType;
	}
}
